// HSS.Logging.Management.LogViewerListView.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       LogViewerListView.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Logging.Management
{
	#region Using Directives
	using System;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.Diagnostics;
	using System.Drawing;
	using System.IO;
	using System.Linq;
	using System.Windows.Forms;
	using HSS.Data;
	using HSS.Forms;
	#endregion

	#region LogViewerListView
	internal sealed partial class LogViewerListView : HSS.Forms.Docking.DockContent
	{
		#region Delegates
		delegate void InitializeEntriesCompletedDel(IAsyncResult Result);
		delegate void InitializeCategoryCompletedDel(IAsyncResult Result);
		#endregion

		#region Events
		/// <summary>
		/// An event that is fired when the selected Item changes
		/// </summary>
		public event EventHandler<SelectedItemEventArgs> SelectionChanged;
		private void OnSelectionChanged(LogEntry entry)
		{
			if (null != SelectionChanged)
				SelectionChanged(this, new SelectedItemEventArgs(entry));
		}
		/// <summary>
		/// An event that is fired when an Item is double clicked
		/// </summary>
		public event EventHandler<SelectedItemEventArgs> ItemDoubleClicked;
		private void OnItemDoubleClicked(LogEntry entry)
		{
			if (null != ItemDoubleClicked)
				ItemDoubleClicked(this, new SelectedItemEventArgs(entry));
		}

		/// <summary>
		/// Event fired once initialized, indication success or failure
		/// </summary>
		public event EventHandler<LogViewerInitializedEventArgs> Initialized;
		private void OnInitialized(bool Success, Exception failure)
		{
			if (null != Initialized)
			{
				System.ComponentModel.ISynchronizeInvoke synchronizer;
				synchronizer = Initialized.Target as System.ComponentModel.ISynchronizeInvoke;
				if (synchronizer != null) //A Windows Forms object
				{
					if (synchronizer.InvokeRequired == false)
					{
						Initialized.DynamicInvoke(new object[] { this, new LogViewerInitializedEventArgs(Success, failure) });
						return;
					}
					try
					{
						synchronizer.Invoke(Initialized, new object[] { this, new LogViewerInitializedEventArgs(Success, failure) });
					}
					catch (Exception ex)
					{
						Trace.WriteLine(ex.ToString());
					}
				}
				else //Not a Windows Forms object
				{
					Initialized.DynamicInvoke(new object[] { this, new LogViewerInitializedEventArgs(Success, failure) });
				}
			}
		}
		#endregion

		#region Fields

		static readonly DateTime minDate = new DateTime(1753, 1, 1);
		static readonly DateTime maxDate = new DateTime(9998, 12, 31);

		const string defaultAppNameText = "Enter App Name ...";
		const string defaultRefNumText = "Enter Ref. Number ...";
		const string defaultUserText = "Enter User Name ...";
		const int dateTimeCol = 1;

		int pages = 0;
		int page = 1;
		int recPerPageDefault = 10;
		int filterSize = 120;

		int eventTypeClmIndex = 0;
		int eventTimeClmIndex = 1;
		int eventCategoryClmIndex = 2;
		int eventAppNameClmIndex = 3;
		int eventRefNumClmIndex = 4;
		int eventUserClmIndex = 5;
		int eventAttachmentClmIndex = 6;
		int eventIdClmIndex = 7;

		bool initialized = false;
		bool columnsInitialized = false;
		bool changingSelectedIndex;
		bool viewSet = false;
		bool viewSavedLog = false;

		DateTime beginDate = minDate;
		DateTime endDate = maxDate;
		ListViewItem foundItem;

		string searchStr = string.Empty;
		string origNoItemsMessage = string.Empty;

		List<LogRecord> unFilteredList;

		#endregion

		#region Constructor
		/// <summary>
		/// Constructor
		/// </summary>
		public LogViewerListView()
		{
			InitializeComponent();
			this.pnlFilter.Height = 0;
			this.origNoItemsMessage = this.lsvEventLog.NoItemsMessage;
			this.btnApply.Enabled = false;
			this.btnResetFilter.Enabled = false;
			this.tlsPager.Visible = false;
			this.Activated += new EventHandler(LogViewerListView_Activated);
		}
		void LogViewerListView_Activated(object sender, EventArgs e)
		{
			this.OnSelectionSet();
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the SqlLogReader for the LogListView
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public SqlLogReader Reader
		{
			get { return this._sqlReader; }
			set
			{
				if (viewSet && viewSavedLog)
					return;
				if (this._sqlReader != value)
				{
					this._sqlReader = value;
					if (!viewSet)
					{
						if (this.lsvEventLog.ViewName != "CurrentLog")
							this.lsvEventLog.ViewName = "CurrentLog";
						viewSet = true;
					}
					Application.DoEvents();
					this.InitializeViewer();
				}
			}
		} SqlLogReader _sqlReader;
		/// <summary>
		/// Gets or sets the File containing log entries for the LogListView
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public string FileName
		{
			get { return this._fileName; }
			set
			{
				if (viewSet && !viewSavedLog)
					return;
				viewSavedLog = true;
				if (this._fileName != value)
				{
					this._fileName = value;
					if (!viewSet)
					{
						string viewName = Path.GetFileNameWithoutExtension(this._fileName);
						if (this.lsvEventLog.ViewName != viewName)
							this.lsvEventLog.ViewName = viewName;
						viewSet = true;
					}
					if (!this.DesignMode)
						this.InitializeViewer();
				}
			}
		} string _fileName;
		/// <summary>
		/// Gets or sets whether or not the filter section is visible
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool FilterVisible
		{
			get { return !(this.pnlFilter.Height == 0); }
			set
			{
				if (value)
					this.pnlFilter.Height = filterSize;
				else
					this.pnlFilter.Height = 0;
			}
		}
		/// <summary>
		/// Returns whether or not it has been successfully initialized
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool IsInitialized
		{
			get { return this.initialized; }
		}

		/// <summary>
		/// If true will automatically read from the SqlLogReader when set
		/// </summary>
		[Category("Behavior")]
		[Description("If true will automatically read from the SqlLogReader when set")]
		[DefaultValue(false)]
		public bool AutoLoadReader
		{
			get { return _autoLoadReader; }
			set { _autoLoadReader = value; }
		} bool _autoLoadReader;
		#endregion

		#region Public Methods

		/// <summary>
		/// Refresh the list of Entries from the source log
		/// </summary>
		/// <returns>The number of records retrieved</returns>
		public bool RefreshLog()
		{
			if (!this.initialized)
				return false;

			if (this.viewSavedLog)
			{
				this.RefreshLogFile();
				return true;
			}

			this.Cursor = Cursors.WaitCursor;
			try
			{
				#region Reset find criteria
				this.foundItem = null;
				this.searchStr = string.Empty;
				#endregion

				#region Get Entries from Database

				#region Parameters

				#region Records per page

				if (this.cboRecsPerPage.Text.Length == 0)
					this.cboRecsPerPage.Text = recPerPageDefault.ToString();
				int recsperpage = recPerPageDefault;
				try
				{
					recsperpage = int.Parse(this.cboRecsPerPage.Text);
					if (recsperpage < 1)
					{
						recsperpage = recPerPageDefault;
						this.cboRecsPerPage.Text = recPerPageDefault.ToString();
					}
				}
				catch
				{
					recsperpage = recPerPageDefault;
					this.cboRecsPerPage.Text = recPerPageDefault.ToString();
				}
				#endregion

				#region Application Name
				string appName = this.cboAppName.Text;

				if (appName != defaultAppNameText)
				{
					if (appName.ToLowerInvariant() == "all")
						appName = string.Empty;

					else if (appName.ToLowerInvariant() == "na")
						appName = string.Empty;

					else if (appName.ToLowerInvariant() == "n/a")
						appName = string.Empty;
				}
				else
				{
					appName = string.Empty;
				}
				#endregion

				#region Reference Number
				string refNum = this.cboRefNumber.Text;

				if (refNum != defaultRefNumText)
				{
					if (refNum.ToLowerInvariant() == "all")
						refNum = string.Empty;

					else if (refNum.ToLowerInvariant() == "na")
						refNum = string.Empty;

					else if (refNum.ToLowerInvariant() == "n/a")
						refNum = string.Empty;
				}
				else
				{
					refNum = string.Empty;
				}
				#endregion

				#region User Name
				string userName = this.cboUserName.Text;
				if (userName == defaultUserText)
					userName = string.Empty;
				#endregion

				#region Event Type Mask
				int events = 0;
				if (this.chkError.Checked)
					events |= int.Parse(this.chkError.Tag.ToString());
				if (this.chkFailure.Checked)
					events |= int.Parse(this.chkFailure.Tag.ToString());
				if (this.chkInformation.Checked)
					events |= int.Parse(this.chkInformation.Tag.ToString());
				if (this.chkSuccess.Checked)
					events |= int.Parse(this.chkSuccess.Tag.ToString());
				if (this.chkWarning.Checked)
					events |= int.Parse(this.chkWarning.Tag.ToString());
				if (events == 0)
					events = 31;
				#endregion

				#endregion

				var data = this._sqlReader.GetEntries(ref this.pages, this.page, recsperpage, events, appName, refNum, this.cboCategories.Text, userName, beginDate, endDate);

				#region Format Display

				this.tlsPager_Page.Text = this.page.ToString();
				this.tlsPager_Pages.Text = this.pages.ToString();

				// Load the data into the DataListView
				this.lsvEventLog.LoadData(data);

				// Select the first Row
				if (this.lsvEventLog.Items.Count > 0)
				{
					this.lsvEventLog.Items[0].Selected = true; // Triggers the OnSelectionChanged Event
					this.lsvEventLog.Focus();
				}
				else
				{
					this.OnSelectionChanged(null);
				}
				this.lblHeaderInfo.Text = " Events Found [ " + this.lsvEventLog.Items.Count.ToString() + " ]";

				#endregion

				#endregion

				return true;
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message, "Unknown Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				this.Cursor = Cursors.Default;
				this.lsvEventLog.Focus();
			}

			return false;
		}
		/// <summary>
		/// Save the current list of entries to a file
		/// </summary>
		public void SaveLog()
		{
			string fileName = GetSaveFileName();
			if (!string.IsNullOrEmpty(fileName))
				this.SaveEntries(fileName, this.lsvEventLog.GetData().OfType<LogRecord>().ToList());
		}
		/// <summary>
		/// Save just the selected entries
		/// </summary>
		public void SaveSelectedEntries()
		{
			string fileName = GetSaveFileName();
			if (!string.IsNullOrEmpty(fileName))
				this.SaveEntries(fileName, this.lsvEventLog.GetSelectedData().OfType<LogRecord>().ToList());
		}
		/// <summary>
		/// Find the entry containing the desired text
		/// </summary>
		/// <param name="SearchText">The text to search for</param>
		/// <returns>true if an item was found containing the text desired; otherwise false</returns>
		public bool FindInList(string SearchText)
		{
			bool found = false;

			this.searchStr = SearchText;
			if (!string.IsNullOrEmpty(searchStr))
			{
				this.foundItem = this.lsvEventLog.FindItemWithText(this.searchStr, true, 0);

				if (null != this.foundItem)
				{
					found = true;
					this.lsvEventLog.SelectedItems.Clear();
					this.lsvEventLog.Focus();
					this.foundItem.EnsureVisible();
					this.foundItem.Selected = true;
					this.foundItem.Focused = true;
				}
			}

			return found;
		}
		/// <summary>
		/// Continue searching for more items for the current search criteria
		/// </summary>
		/// <returns>true if another entry was found; otherwise false</returns>
		public bool FindNextInList()
		{
			bool found = false;

			if (string.IsNullOrEmpty(this.searchStr))
				return found;

			if (null != this.foundItem)
			{
				int index = this.foundItem.Index + 1;
				if (index > this.lsvEventLog.Items.Count - 1)
					index = 0;
				this.foundItem = this.lsvEventLog.FindItemWithText(this.searchStr, true, index);
			}
			else
				this.foundItem = this.lsvEventLog.FindItemWithText(this.searchStr, true, 0);

			if (null != this.foundItem)
			{
				found = true;
				this.lsvEventLog.SelectedItems.Clear();
				this.lsvEventLog.Focus();
				this.foundItem.EnsureVisible();
				this.foundItem.Selected = true;
				this.foundItem.Focused = true;
			}

			return found;

		}
		#endregion

		#region Private Methods
		private void InitializeViewer()
		{
			try
			{
				this.CommonInitialization();

				if (viewSavedLog)
					this.InitializeViewFromFile();
				else
					this.InitializeViewFromDb();

				Application.DoEvents();
				this.OnSelectionSet();

				this.initialized = true;
				this.OnInitialized(true, null);
			}
			catch (Exception ex)
			{
				this.initialized = false;
				this.OnInitialized(false, ex);
			}
			finally
			{
				this.InitializationComplete();
			}
		}
		private void CommonInitialization()
		{
			this.Cursor = Cursors.WaitCursor;
			this.lsvEventLog.NoItemsMessage = "Please wait while initializing the viewer ...";
			this.tlsPager_Page.Text = "0";
			this.tlsPager_Pages.Text = "0";
			this.InitializeColumns();
		}
		private void InitializationComplete()
		{
			if (this.InvokeRequired)
			{
				try { this.Invoke(new MethodInvoker(InitializationComplete)); }
				catch { throw; }
				return;
			}
			if (this.initialized)
				this.lsvEventLog.NoItemsMessage = origNoItemsMessage;
			else
				this.lsvEventLog.NoItemsMessage = "Exceptions encountered initializing current database log";
			this.btnApply.Enabled = this.initialized;
			this.btnResetFilter.Enabled = this.initialized;
			this.Cursor = Cursors.Default;
		}

		private void InitializeViewFromDb()
		{
			this.cboCategories.Visible = true;
			this.lblCategory.Visible = true;
			this.cboLogTime.Visible = true;
			this.lblLoggedLabel.Visible = true;

			this.cboAppName.Text = defaultAppNameText;
			this.cboRefNumber.Text = defaultRefNumText;
			this.cboUserName.Text = defaultUserText;
			this.cboLogTime.SelectedIndex = 0;

			string dbName = new DataAccessConnection(this._sqlReader.LogConfig.DbConnString).InitialCatalog;
			this.lblDbName.Text = "Database [ " + dbName + " ]";

			this.InitializeCategories();
			if (this.AutoLoadReader)
				this.InitializeDbEntries();

			this.tlsPager.Visible = true;

		}
		private void InitializeViewFromFile()
		{
			this.cboCategories.Visible = false;
			this.lblCategory.Visible = false;
			this.cboLogTime.Visible = false;
			this.lblLoggedLabel.Visible = false;
			this.lblDbName.Text = "Saved Log [ " + Path.GetFileName(this._fileName) + " ]";
			this.RefreshLogFile();
		}
		private void InitializeCategories()
		{
			IAsyncResult res = this._sqlReader.BeginGetCategories(null);

			while (!res.AsyncWaitHandle.WaitOne(100, false)) { Application.DoEvents(); }

			try
			{
				List<LogCategory> dr = SqlLogReader.EndGetCategories(res);

				if (null != dr)
					ModuleBase.InitializeComboBox(this.cboCategories, dr.ToArray(), false, true);

				this.ResetSelectedCatoregory();
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				MessageBox.Show(ex.Message);
			}
		}
		private void InitializeDbEntries()
		{
			this.page = 1;

			int recsperpage = recPerPageDefault;
			int events = 31;
			string appName = string.Empty;
			string refNum = string.Empty;
			string category = string.Empty;
			string userName = string.Empty;

			IAsyncResult res = this._sqlReader.BeginGetEntries(null, 1, recsperpage, events, appName, refNum, category, userName, beginDate, endDate);

			while (!res.AsyncWaitHandle.WaitOne(100, false)) { Application.DoEvents(); }

			try
			{
				var dt = SqlLogReader.EndGetEntries(res, ref this.pages);

				// Update Page/Pages
				this.tlsPager_Page.Text = this.page.ToString();
				this.tlsPager_Pages.Text = this.pages.ToString();

				if (null != dt)
				{
					// Load the data into the DataListView
					this.lsvEventLog.LoadData(dt);

					// Select the first Row
					if (this.lsvEventLog.Items.Count > 0)
					{
						this.lsvEventLog.Items[0].Selected = true; // Triggers the OnSelectionChanged Event
						this.lsvEventLog.Focus();
					}
					else
					{
						this.OnSelectionChanged(null);
					}

					// Display Count
					this.lblHeaderInfo.Text = " Events Found [ " + this.lsvEventLog.Items.Count.ToString() + " ]";
				}
				else
				{
					this.lsvEventLog.Items.Clear();
				}
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				MessageBox.Show(ex.Message);
			}
		}
		private void InitializeColumns()
		{
			if (this.columnsInitialized)
				return;

			#region Columns

			((DataListColumn)this.lsvEventLog.Columns[0]).TagGetter = delegate(IDataContainer row) { return ((LogRecord)row).Message; };

			#region EventId
			this.eventIdClmIndex = this.clhEventID.DisplayIndex;
			this.clhEventID.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).EventId; };
			this.clhEventID.GroupKeyGetter = delegate(IDataContainer row) { return ((LogRecord)row).EventId; };
			this.clhEventID.GroupKeyToTitleConverter = delegate(object groupKey) { return "EventId:  " + groupKey.ToString(); };
			#endregion

			#region EventType
			this.eventTypeClmIndex = this.clhEventType.DisplayIndex;
			this.clhEventType.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).EventType; };
			this.clhEventType.GroupKeyGetter = delegate(IDataContainer row) { return ((LogRecord)row).EventType; };
			this.clhEventType.GroupKeyToTitleConverter = delegate(object groupKey) { return "EventType:  " + groupKey.ToString(); };
			this.clhEventType.ImageGetter = delegate(IDataContainer row)
			{
				LogRecord r = (LogRecord)row;
				string eventType = r.EventType;
				return GetEventTypeImageIndex(eventType);
			};
			#endregion

			#region Category
			this.eventCategoryClmIndex = this.clhCategory.DisplayIndex;
			this.clhCategory.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).Category; };
			this.clhCategory.GroupKeyGetter = delegate(IDataContainer row) { return ((LogRecord)row).Category; };
			this.clhCategory.GroupKeyToTitleConverter = delegate(object groupKey) { return "Category:  " + groupKey.ToString(); };
			#endregion

			#region ApplicationName
			this.eventAppNameClmIndex = this.clhApplicationName.DisplayIndex;
			this.clhApplicationName.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).ApplicationName; };
			this.clhApplicationName.ValueToStringConverter = delegate(object value)
			{
				if (null == value)
					return "N/A";
				else
				{
					string retVal = value.ToString();
					if (string.IsNullOrEmpty(retVal))
						return "N/A";
					else
						return retVal;
				}
			};
			this.clhApplicationName.GroupKeyGetter = delegate(IDataContainer row)
			{
				object value = ((LogRecord)row).ApplicationName;

				if (null == value)
					return "N/A";
				else
				{
					string retVal = value.ToString();
					if (string.IsNullOrEmpty(retVal))
						return "N/A";
					else
						return retVal;
				}
			};
			this.clhApplicationName.GroupKeyToTitleConverter = delegate(object groupKey)
			{
				return "Application:  " + groupKey.ToString();
			};
			#endregion

			#region Ref. Number
			this.eventRefNumClmIndex = this.clhReferenceNumber.DisplayIndex;
			this.clhReferenceNumber.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).ReferenceNumber; };
			this.clhReferenceNumber.ValueToStringConverter = delegate(object value)
			{
				if (null == value)
					return "N/A";
				else
				{
					string retVal = value.ToString();
					if (string.IsNullOrEmpty(retVal))
						return "N/A";
					else
						return retVal;
				}
			};
			this.clhReferenceNumber.GroupKeyGetter = delegate(IDataContainer row)
			{
				object value = ((LogRecord)row).ReferenceNumber;

				if (null == value)
					return "N/A";
				else
				{
					string retVal = value.ToString();
					if (string.IsNullOrEmpty(retVal))
						return "N/A";
					else
						return retVal;
				}
			};
			this.clhReferenceNumber.GroupKeyToTitleConverter = delegate(object groupKey)
			{
				return "Ref. Number:  " + groupKey.ToString();
			};
			#endregion

			#region User
			this.eventUserClmIndex = this.clhUserName.DisplayIndex;
			this.clhUserName.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).UserName; };
			this.clhUserName.GroupKeyGetter = delegate(IDataContainer row) { return ((LogRecord)row).UserName; };
			this.clhUserName.GroupKeyToTitleConverter = delegate(object groupKey) { return "Logged by User:  " + groupKey.ToString(); };
			#endregion

			#region DateTime
			this.eventTimeClmIndex = this.clhCreatedDate.DisplayIndex;
			this.clhCreatedDate.ValueGetter = delegate(IDataContainer row) { return ((LogRecord)row).CreatedDate; };
			this.clhCreatedDate.ValueToStringConverter = delegate(object value)
			{
				DateTime valDT = (DateTime)value;
				return valDT.ToString();
			};
			this.clhCreatedDate.GroupKeyGetter = delegate(IDataContainer row) { return ((DateTime)((LogRecord)row).CreatedDate).Date; };
			this.clhCreatedDate.GroupKeyToTitleConverter = delegate(object groupKey) { return "Date:  " + ((DateTime)groupKey).ToLongDateString(); };
			#endregion

			#region Attachment
			this.eventAttachmentClmIndex = this.clhAttachment.DisplayIndex;
			this.clhAttachment.ValueGetter = delegate(IDataContainer row)
			{
				string attach = ((LogRecord)row).ViewAttachment;
				attach = attach.Replace("AttachmentViewer.aspx?AttachmentId=", string.Empty);
				if (attach.Length > 0)
					return int.Parse(attach);
				else
					return 0;
			};
			this.clhAttachment.ValueToStringConverter = delegate(object value)
			{
				int attach = (int)value;
				if (attach > 0)
					return "YES";
				else
					return "NO";
			};
			this.clhAttachment.TagGetter = delegate(IDataContainer row)
			{
				string attach = ((LogRecord)row).ViewAttachment;
				attach = attach.Replace("AttachmentViewer.aspx?AttachmentId=", string.Empty);
				if (attach.Length > 0)
					return int.Parse(attach); // This is the AttachmentId
				else
					return 0;
			};
			this.clhAttachment.GroupKeyGetter = delegate(IDataContainer row)
			{
				string attach = ((LogRecord)row).ViewAttachment;
				attach = attach.Replace("AttachmentViewer.aspx?AttachmentId=", string.Empty);
				if (attach.Length > 0)
					return int.Parse(attach);
				else
					return 0;
			};
			this.clhAttachment.GroupKeyToTitleConverter = delegate(object groupKey)
			{
				int attach = (int)groupKey;
				if (attach > 0)
					return "Entries with an Attachment";
				else
					return "Entries without an Attachment";
			};
			#endregion

			#endregion

			this.columnsInitialized = true;

		}

		private int GetEventTypeImageIndex(string EventType)
		{
			switch (EventType)
			{
				case "Warning":
					return 0;
				case "Error":
					return 1;
				case "FailureAudit":
					return 2;
				case "Information":
					return 3;
				case "SuccessAudit":
					return 4;
				default:
					return 3;
			}
		}
		private void SaveEntries(string fileName, List<LogRecord> records)
		{
			if (string.IsNullOrEmpty(fileName))
				return;

			if (null == records || records.Count == 0)
				return;

			string ext = Path.GetExtension(fileName);
			try
			{
				if (ext == ".hsslx")
					ObjectSerialization.ToXmlFile(records, fileName);
				else if (ext == ".hsslb")
					ObjectSerialization.ToFile(records, fileName);
				else
					MessageBox.Show("Unknown file type. The selected Entries could not be save.", "Save selected Entries", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.ToString());
				MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
		private void RefreshLogFile()
		{
			List<LogRecord> records;
			try
			{
				string ext = Path.GetExtension(this._fileName);
				if (ext == ".hsslx")
				{
					records = ObjectSerialization.FromXml<List<LogRecord>>(new FileInfo(this._fileName));
				}
				else if (ext == ".hsslb")
				{
					records = ObjectSerialization.FromBinary<List<LogRecord>>(new FileInfo(this._fileName));
				}
				else
				{
					Trace.WriteLine("Unknown file type. The File cannot be opened.");
					MessageBox.Show("Unknown file type. The File cannot be opened.", "Open Log File", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				unFilteredList = records;

				//Clear the list first...
				this.lsvEventLog.Items.Clear();

				if (null != unFilteredList)
				{
					// Load the data into the DataListView
					this.lsvEventLog.LoadData(unFilteredList);

					// Select the first Row
					if (this.lsvEventLog.Items.Count > 0)
						this.lsvEventLog.Items[0].Selected = true;
				}

				this.lblHeaderInfo.Text = " Events Found [ " + this.lsvEventLog.Items.Count.ToString() + " ]";

			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.ToString());
				MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}
		private void FilterLogFile()
		{

			#region Event Type

			var recordFilter = unFilteredList.Where(FilterLogRecord).ToList();

			#endregion

			#region User Name

			string userName = this.cboUserName.Text;
			if (userName == defaultUserText)
				userName = string.Empty;

			if (!string.IsNullOrEmpty(userName))
			{
				recordFilter = (from r in recordFilter
								where r.UserName == userName
								select r).ToList();
			}
			#endregion

			#region AppName

			string appName = this.cboAppName.Text;

			if (appName != defaultRefNumText)
			{
				if (appName.ToLowerInvariant() == "all")
					appName = string.Empty;

				else if (appName.ToLowerInvariant() == "na")
					appName = string.Empty;

				else if (appName.ToLowerInvariant() == "n/a")
					appName = string.Empty;
			}
			else
			{
				appName = string.Empty;
			}

			if (!string.IsNullOrEmpty(appName))
			{
				if (appName == "NULL")
				{
					recordFilter = (from r in recordFilter
									where string.IsNullOrEmpty(r.ApplicationName)
									select r).ToList();
				}
				else if (appName == "NOT NULL")
				{
					recordFilter = (from r in recordFilter
									where !string.IsNullOrEmpty(r.ApplicationName) && !string.IsNullOrWhiteSpace(r.ApplicationName)
									select r).ToList();
				}
				else
				{
					recordFilter = (from r in recordFilter
									where r.ApplicationName == appName
									select r).ToList();
				}
			}
			#endregion

			#region Reference Number

			string refNum = this.cboRefNumber.Text;

			if (refNum != defaultRefNumText)
			{
				if (refNum.ToLowerInvariant() == "all")
					refNum = string.Empty;

				else if (refNum.ToLowerInvariant() == "na")
					refNum = string.Empty;

				else if (refNum.ToLowerInvariant() == "n/a")
					refNum = string.Empty;
			}
			else
			{
				refNum = string.Empty;
			}

			if (!string.IsNullOrEmpty(refNum))
			{
				if (refNum == "NULL")
				{
					recordFilter = (from r in recordFilter
									where string.IsNullOrEmpty(r.ReferenceNumber)
									select r).ToList();
				}
				else if (refNum == "NOT NULL")
				{
					recordFilter = (from r in recordFilter
									where !string.IsNullOrEmpty(r.ReferenceNumber) && !string.IsNullOrWhiteSpace(r.ReferenceNumber)
									select r).ToList();
				}
				else
				{
					recordFilter = (from r in recordFilter
									where r.ReferenceNumber == refNum
									select r).ToList();
				}
			}
			#endregion

			LogRecord[] rows = recordFilter.ToArray();

			//Clear the list first...
			this.lsvEventLog.Items.Clear();

			if (null != rows)
			{
				// Load the data into the DataListView
				this.lsvEventLog.LoadData(rows);

				// Select the first Row
				if (this.lsvEventLog.Items.Count > 0)
					this.lsvEventLog.Items[0].Selected = true;
			}

			this.lblHeaderInfo.Text = " Events Found [ " + this.lsvEventLog.Items.Count.ToString() + " ]";

		}
		private bool FilterLogRecord(LogRecord record)
		{
			if (this.chkError.Checked && record.EventType == "Error")
				return true;

			else if (this.chkFailure.Checked && record.EventType == "FailureAudit")
				return true;

			else if (this.chkInformation.Checked && record.EventType == "Information")
				return true;

			else if (this.chkSuccess.Checked && record.EventType == "SuccessAudit")
				return true;

			else if (this.chkWarning.Checked && record.EventType == "Warning")
				return true;

			else
				return !(this.chkError.Checked | this.chkFailure.Checked | this.chkInformation.Checked | this.chkSuccess.Checked | this.chkWarning.Checked);
		}
		private void OnSelectionSet()
		{
			if (changingSelectedIndex)
				return;

			changingSelectedIndex = true;

			try
			{
				if (this.lsvEventLog.SelectedItems.Count > 0)
				{
					LogEntry entry = this.BuildEntryFromItem(this.lsvEventLog.SelectedItems[0]);
					this.OnSelectionChanged(entry);
				}
				else
				{
					this.OnSelectionChanged(null);
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.ToString());
			}
			finally
			{
				changingSelectedIndex = false;
			}
		}
		private void OnDoubleClicked()
		{
			try
			{
				if (this.lsvEventLog.SelectedItems.Count > 0)
				{
					LogEntry entry = this.BuildEntryFromItem(this.lsvEventLog.SelectedItems[0]);
					this.OnItemDoubleClicked(entry);
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.ToString());
			}
		}
		private void ResetFilter()
		{
			this.chkError.Checked = false;
			this.chkFailure.Checked = false;
			this.chkInformation.Checked = false;
			this.chkSuccess.Checked = false;
			this.chkWarning.Checked = false;
			this.cboAppName.Text = defaultAppNameText;
			this.cboAppName.ForeColor = Color.FromKnownColor(KnownColor.ControlDark);
			this.cboRefNumber.Text = defaultRefNumText;
			this.cboRefNumber.ForeColor = Color.FromKnownColor(KnownColor.ControlDark);
			this.cboUserName.Text = defaultUserText;
			this.cboUserName.ForeColor = Color.FromKnownColor(KnownColor.ControlDark);
			this.ResetSelectedCatoregory();
			this.cboLogTime.SelectedIndex = 0;
			this.beginDate = minDate;
			this.endDate = maxDate;
			if (this.viewSavedLog)
				this.RefreshLogFile();
			else
			{
				this.page = 1;
				this.RefreshLog();
			}
		}
		private void ResetSelectedCatoregory()
		{
			if (this.cboCategories.Items.Count > 0)
			{
				ValueMember defaultItem = null;
				foreach (ValueMember item in this.cboCategories.Items)
				{
					if (item.TextDisplay.ToLower() == "all")
					{
						defaultItem = item;
						break;
					}
				}
				this.cboCategories.SelectedItem = defaultItem;
			}
		}
		private void BuildViewSortByMenu(ToolStripMenuItem mi)
		{
			ToolStripMenuItem miChild;

			bool isChecked = false;
			foreach (DataListColumn col in this.lsvEventLog.Columns)
			{
				miChild = mi.DropDownItems.Add(col.Text) as ToolStripMenuItem;
				if (!isChecked && this.lsvEventLog.IsSorted)
				{
					isChecked = col.Index == this.lsvEventLog.ArrangedBy && this.lsvEventLog.SortOrder != SortOrder.None;
					miChild.Checked = isChecked;
				}
				miChild.Enabled = this.lsvEventLog.AllowSort;
			}
			if (isChecked && this.lsvEventLog.AllowSort)
			{
				miChild = mi.DropDownItems.Add("(None)") as ToolStripMenuItem;
				miChild.Enabled = this.lsvEventLog.AllowSort;
			}

			mi.DropDownItems.Add("-");

			bool sorted = this.lsvEventLog.AllowSort && this.lsvEventLog.IsSorted && this.lsvEventLog.SortOrder != SortOrder.None;
			miChild = mi.DropDownItems.Add("Ascending") as ToolStripMenuItem;
			miChild.Checked = sorted && this.lsvEventLog.SortOrder == SortOrder.Ascending;
			miChild.Enabled = sorted;

			miChild = mi.DropDownItems.Add("Descending") as ToolStripMenuItem;
			miChild.Checked = sorted && this.lsvEventLog.SortOrder == SortOrder.Descending;
			miChild.Enabled = sorted;

		}
		private void BuildViewGroupByMenu(ToolStripMenuItem mi)
		{
			ToolStripMenuItem miChild;

			bool isChecked = false;
			foreach (DataListColumn col in this.lsvEventLog.Columns)
			{
				miChild = mi.DropDownItems.Add(col.Text) as ToolStripMenuItem;
				if (!isChecked && this.lsvEventLog.IsGrouped)
				{
					isChecked = col.Index == this.lsvEventLog.ArrangedBy && this.lsvEventLog.SortOrder != SortOrder.None;
					miChild.Checked = isChecked;
				}
				miChild.Enabled = this.lsvEventLog.AllowShowGroups;
			}
			if (isChecked && this.lsvEventLog.AllowShowGroups)
			{
				miChild = mi.DropDownItems.Add("(None)") as ToolStripMenuItem;
				miChild.Enabled = this.lsvEventLog.AllowShowGroups;
			}

			mi.DropDownItems.Add("-");

			bool grouped = this.lsvEventLog.AllowShowGroups && this.lsvEventLog.IsGrouped && isChecked && this.lsvEventLog.SortOrder != SortOrder.None;

			miChild = mi.DropDownItems.Add("Ascending") as ToolStripMenuItem;
			miChild.Checked = grouped && this.lsvEventLog.SortOrder == SortOrder.Ascending;
			miChild.Enabled = grouped && this.lsvEventLog.View != View.List;

			miChild = mi.DropDownItems.Add("Descending") as ToolStripMenuItem;
			miChild.Checked = grouped && this.lsvEventLog.SortOrder == SortOrder.Descending;
			miChild.Enabled = grouped && this.lsvEventLog.View != View.List;

		}
		private string GetEventTypeImageKey(string EventType)
		{
			switch (EventType)
			{
				case "Error":
					return "eventlogError";
				case "Warning":
					return "eventlogWarn";
				case "Information":
					return "eventlogInfo";
				case "SuccessAudit":
					return "eventlogSuccessAudit";
				case "FailureAudit":
					return "eventlogFailureAudit";
				default:
					return "eventlogInfo";
			}
		}
		private string GetSaveFileName()
		{
			string fileName = string.Empty;
			using (SaveFileDialog f = new SaveFileDialog())
			{
				f.Filter = "HSS Log Xml File (*.hsslx)|*.hsslx|HSS Log Binary File (*.hsslb)|*.hsslb";
				f.DefaultExt = ".xml";
				if (f.ShowDialog(this.ParentForm) == DialogResult.OK)
					fileName = f.FileName;
			}
			return fileName;
		}
		private LogEntry BuildEntryFromItem(ListViewItem Item)
		{
			LogEntry entry = new LogEntry();
			entry.Message = Item.Tag.ToString();
			entry.EventId = int.Parse(Item.SubItems[eventIdClmIndex].Text);
			entry.EventType = (EventLogEntryType)Enum.Parse(typeof(EventLogEntryType), Item.SubItems[eventTypeClmIndex].Text);
			entry.Category = Item.SubItems[eventCategoryClmIndex].Text;
			entry.ApplicationName = Item.SubItems[eventAppNameClmIndex].Text;
			entry.ReferenceNumber = Item.SubItems[eventRefNumClmIndex].Text;
			entry.User = Item.SubItems[eventUserClmIndex].Text;
			entry.CreatedDate = DateTime.Parse(Item.SubItems[eventTimeClmIndex].Text);
			entry.AttachmentId = (int)Item.SubItems[eventAttachmentClmIndex].Tag;

			return entry;

		}

		#endregion

		#region Event Handlers

		#region Toolbar

		private void tlsPager_FirstPage_Click(object sender, EventArgs e)
		{
			this.page = 1;
			this.RefreshLog();
		}
		private void tlsPager_PrevPage_Click(object sender, EventArgs e)
		{
			if (this.page > 1)
				this.page--;
			else
				this.page = this.pages;

			this.RefreshLog();
		}
		private void tlsPager_Page_KeyUp(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				int newPage = 1;
				if (int.TryParse(this.tlsPager_Page.Text, out newPage))
				{
					if (newPage > this.pages)
						MessageBox.Show("Page cannot be greater then the number of available Pages.", "Event Viewer", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
				this.page = newPage;
				this.RefreshLog();
			}
		}
		private void cboRecsPerPage_KeyPress(object sender, KeyPressEventArgs e)
		{
			if (e.KeyChar == (char)13)
				this.RefreshLog();
		}
		private void cboRecsPerPage_SelectedIndexChanged(object sender, EventArgs e)
		{
			this.RefreshLog();
		}
		private void tlsPager_NextPage_Click(object sender, EventArgs e)
		{
			if (this.page < this.pages)
				this.page++;
			else
				this.page = 1;

			this.RefreshLog();
		}
		private void tlsPager_LastPage_Click(object sender, EventArgs e)
		{
			this.page = this.pages;
			this.RefreshLog();
		}

		#endregion

		#region Context Menu Handlers

		private void ctxListView_Opening(object sender, CancelEventArgs e)
		{
			e.Cancel = true;

			if (!this.initialized)
				return;

			if (this.lsvEventLog.Items.Count == 0)
				return;

			#region Arrange By - Column Name
			this.ctxListView_SortBy.DropDownItems.Clear();
			this.BuildViewSortByMenu(this.ctxListView_SortBy);
			this.ctxListView_SortBy.Visible = true;

			this.ctxListView_GroupBy.DropDownItems.Clear();
			this.BuildViewGroupByMenu(this.ctxListView_GroupBy);
			this.ctxListView_GroupBy.Visible = true;
			#endregion

			e.Cancel = false;
		}
		private void ListView_SortBy(object sender, ToolStripItemClickedEventArgs e)
		{
			if (!(e.ClickedItem is ToolStripMenuItem))
				return;

			// At this point in time, even though the user Clicked the
			// the menu item, it is not currently toBeChecked, so
			// if it is not checked that means the request is to act as if it
			// is checked or more accurately will be checked.			
			bool Checked = !((ToolStripMenuItem)e.ClickedItem).Checked;
			if (Checked)
			{
				// The Menu Item Clicked
				string text = e.ClickedItem.Text;

				switch (text)
				{
					case "Ascending":
						this.lsvEventLog.SortOrder = SortOrder.Ascending;
						this.lsvEventLog.Sort(this.lsvEventLog.ArrangedBy);
						break;

					case "Descending":
						this.lsvEventLog.SortOrder = SortOrder.Descending;
						this.lsvEventLog.Sort(this.lsvEventLog.ArrangedBy);
						break;

					default:
						// Look for the Column Name matching the Menu Item
						// and if found, then Arrange (Sort) the Groups (Columns) by the
						// Column (Group) requested
						int colIndex = 0;
						DataListColumn col = null;
						if (text == "(None)")
						{
							this.lsvEventLog.SortOrder = SortOrder.None;
							this.lsvEventLog.IsSorted = false;
						}
						else
						{
							col = this.lsvEventLog.Columns[text] as DataListColumn;
							if (null != col) colIndex = col.Index;
							this.lsvEventLog.Sort(colIndex);
						}
						break;
				}
			}
		}
		private void ListView_GroupBy(object sender, ToolStripItemClickedEventArgs e)
		{
			if (!(e.ClickedItem is ToolStripMenuItem))
				return;

			// At this point in time, even though the user Clicked the
			// the menu item, it is not currently toBeChecked, so
			// if it is not checked that means the request is to act as if it
			// is checked or more accurately will be checked.			
			bool toBeChecked = !((ToolStripMenuItem)e.ClickedItem).Checked;
			if (toBeChecked)
			{
				// The Menu Item Clicked
				string text = e.ClickedItem.Text;

				switch (text)
				{
					case "Ascending":
						this.lsvEventLog.SortOrder = SortOrder.Ascending;
						this.lsvEventLog.Group(this.lsvEventLog.ArrangedBy);
						break;

					case "Descending":
						this.lsvEventLog.SortOrder = SortOrder.Descending;
						this.lsvEventLog.Group(this.lsvEventLog.ArrangedBy);
						break;

					default:
						// Look for the Column Name matching the Menu Item
						// and if found, then Arrange (Sort) the Groups (Columns) by the
						// Column (Group) requested
						int colIndex = 0;
						DataListColumn col = null;
						if (text == "(None)")
						{
							this.lsvEventLog.SortOrder = SortOrder.None;
							this.lsvEventLog.IsGrouped = false;
						}
						else
						{
							col = this.lsvEventLog.Columns[text] as DataListColumn;
							if (null != col) colIndex = col.Index;
							this.lsvEventLog.Group(colIndex);
						}
						break;
				}
			}
		}

		#endregion

		private void lsvEventLog_SelectedIndexChanged(object sender, System.EventArgs e)
		{
			if (!this.initialized)
				return;
			this.OnSelectionSet();
		}
		private void lsvEventLog_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			if (!this.initialized)
				return;
			this.OnDoubleClicked();
		}
		private void cboAppName_Enter(object sender, EventArgs e)
		{
			if (this.cboAppName.Text == defaultAppNameText)
				this.cboAppName.Text = string.Empty;
			this.cboAppName.ForeColor = Color.Black;
		}
		private void cboAppName_Leave(object sender, EventArgs e)
		{
			if (this.cboAppName.Text.Length == 0)
				this.cboAppName.Text = defaultAppNameText;

			if (this.cboAppName.Text == defaultAppNameText)
				this.cboAppName.ForeColor = Color.FromKnownColor(KnownColor.ControlDark);
			else
				this.cboAppName.ForeColor = Color.Black;
		}
		private void cboRefNumber_Enter(object sender, EventArgs e)
		{
			if (this.cboRefNumber.Text == defaultRefNumText)
				this.cboRefNumber.Text = string.Empty;
			this.cboRefNumber.ForeColor = Color.Black;
		}
		private void cboRefNumber_Leave(object sender, EventArgs e)
		{
			if (this.cboRefNumber.Text.Length == 0)
				this.cboRefNumber.Text = defaultRefNumText;

			if (this.cboRefNumber.Text == defaultRefNumText)
				this.cboRefNumber.ForeColor = Color.FromKnownColor(KnownColor.ControlDark);
			else
				this.cboRefNumber.ForeColor = Color.Black;
		}
		private void cboUserName_Enter(object sender, EventArgs e)
		{
			if (this.cboUserName.Text == defaultUserText)
				this.cboUserName.Text = string.Empty;
			this.cboUserName.ForeColor = Color.Black;
		}
		private void cboUserName_Leave(object sender, EventArgs e)
		{
			if (this.cboUserName.Text.Length == 0)
				this.cboUserName.Text = defaultUserText;

			if (this.cboUserName.Text == defaultUserText)
				this.cboUserName.ForeColor = Color.FromKnownColor(KnownColor.ControlDark);
			else
				this.cboUserName.ForeColor = Color.Black;
		}
		private void cboLogTime_SelectionChangeCommitted(object sender, EventArgs e)
		{
			switch (this.cboLogTime.SelectedIndex)
			{
				case 0: // = Any Time
					beginDate = minDate;
					endDate = maxDate;
					break;
				case 1: // = Last Hour
					beginDate = DateTime.Now.Subtract(new TimeSpan(1, 0, 0));
					endDate = maxDate;
					break;
				case 2: // = Last 12 Hours
					beginDate = DateTime.Now.Subtract(new TimeSpan(12, 0, 0));
					endDate = maxDate;
					break;
				case 3: // = Last 24 Hours
					beginDate = DateTime.Now.Subtract(new TimeSpan(24, 0, 0));
					endDate = maxDate;
					break;
				case 4: // = Last 7 Days
					beginDate = DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0));
					endDate = maxDate;
					break;
				case 5: // = Last 30 Days
					beginDate = DateTime.Now.Subtract(new TimeSpan(30, 0, 0, 0));
					endDate = maxDate;
					break;
				case 6: // = Custom range...
					using (HSS.Forms.DateRangeSelector range = new HSS.Forms.DateRangeSelector())
					{
						range.BeginDate = beginDate;
						range.EndDate = endDate;

						if (range.ShowDialog(this.ParentForm) == DialogResult.OK)
						{
							beginDate = range.BeginDate;
							endDate = range.EndDate;
						}
					}
					break;
			}
		}
		private void btnApply_Click(object sender, EventArgs e)
		{
			if (!this.initialized)
				return;

			#region App Name

			string appName = this.cboAppName.Text;

			if (appName == defaultRefNumText)
				appName = "ALL";

			else if (appName.ToLowerInvariant() == "all")
				appName = "ALL";

			else if (appName.ToLowerInvariant() == "na")
				appName = "ALL";

			else if (appName.ToLowerInvariant() == "n/a")
				appName = "ALL";

			if (!this.cboAppName.Items.Contains(appName))
				this.cboAppName.Items.Add(appName);

			#endregion

			#region Ref Number

			string refNum = this.cboRefNumber.Text;

			if (refNum == defaultRefNumText)
				refNum = "ALL";

			else if (refNum.ToLowerInvariant() == "all")
				refNum = "ALL";

			else if (refNum.ToLowerInvariant() == "na")
				refNum = "ALL";

			else if (refNum.ToLowerInvariant() == "n/a")
				refNum = "ALL";

			if (!this.cboRefNumber.Items.Contains(refNum))
				this.cboRefNumber.Items.Add(refNum);

			#endregion

			#region User Name

			string userName = this.cboUserName.Text;
			if (userName == defaultUserText)
				userName = string.Empty;
			else if (!this.cboUserName.Items.Contains(userName))
				this.cboUserName.Items.Add(userName);

			#endregion

			if (this.viewSavedLog)
				this.FilterLogFile();
			else
			{
				this.page = 1;
				this.RefreshLog();
			}
		}
		private void btnResetFilter_Click(object sender, EventArgs e)
		{
			this.ResetFilter();
		}
		#endregion
	}
	#endregion
}